/*-------------------------------- Arctic Core ------------------------------
 * Copyright (C) 2013, ArcCore AB, Sweden, www.arccore.com.
 * Contact: <contact@arccore.com>
 * 
 * You may ONLY use this file:
 * 1)if you have a valid commercial ArcCore license and then in accordance with  
 * the terms contained in the written license agreement between you and ArcCore, 
 * or alternatively
 * 2)if you follow the terms found in GNU General Public License version 2 as 
 * published by the Free Software Foundation and appearing in the file 
 * LICENSE.GPL included in the packaging of this file or here 
 * <http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt>
 *-------------------------------- Arctic Core -----------------------------*/

/*----------------------------[information]----------------------------------
 * Author: mahi/hebe
 *
 * Part of Release:
 *   4.0.3
 *
 * Description:
 *   Implements the Can Interface
 *
 * Support:
 *   Private                  Have Support
 *   ---------------------------------------------------------------
 *   CANIF_[PRIVATE_]DLC_CHECK 					Y		4.0.3
 *   CANIF_[PRIVATE_]SOFTWARE_FILTER_TYPE 		N		4.0.3
 *   CANIF_NUMBER_OF_TXBUFFERS  				N		3.1.5
 *   CANIF_PRIVATE_SUPPORT_TTCAN				N       4.0.3
 *
 *
 *   Public                  Have Support
 *   ----------------------------------------------------------------
 *   CANIF_[PUBLIC_]DEV_ERROR_DETECT			Y		4.0.3
 *   CANIF_[PUBLIC_]MULTIPLE_DRIVER_SUPPORT		N		4.0.3
 *   CANIF_[PUBLIC_]NUMBER_OF_CAN_HW_UNITS		N		3.1.5
 *   CANIF_PUBLIC_TXCONFIRM_POLLING_SUPPORT		N		4.0.3
 *   CANIF_[PUBLIC_]READRXPDU_DATA_API			N		4.0.3
 *   CANIF_[PUBLIC_]READRXPDU_NOTIF_STATUS_API	N		4.0.3
 *   CANIF_[PUBLIC_]READTXPDU_NOTIF_STATUS_API	N		4.0.3
 *   CANIF_[PUBLIC_]SETDYNAMICTXID_API			N		4.0.3
 *   CANIF_[PUBLIC_]VERSION_INFO_API			Y		4.0.3
 *
 *   CANIF_PUBLIC_CANCEL_TRANSMIT_SUPPORT		N		4.0.3
 *   CANIF_PUBLIC_CDD_HEADERFILE				N		4.0.3
 *   CANIF_PUBLIC_HANDLE_TYPE_ENUM				N 		4.0.3
 *   CANIF_PUBLIC_TX_BUFFERING					Y 		4.0.3
 *   CANIF_PUBLIC_WAKEUP_CHECK_VALIDATION_API   N 		4.0.3
 *   CANIF_PUBLIC_WAKEUP_CHECK_VALID_BY_NM	    N 		4.0.3
 *
 * Implementation Notes:
 *   Channels:
 *      The specification speaks a lot of channels and it's sometimes confusing
 *      This implementations interpretation is:
 *      - Physical Channel
 *        One physical channel is connected to one CAN controller and one CAN
 *        transceiver. One or more physical channels may be connected to a single
 *        network (the physical CAN network)
 *
 *                physical channel      physical channel
 *                       |                     |
 *                     CAN_B                  CAN_D
 *                       |                     |
 *                       +       NETWORK       +
 *
 *
 *       Since the CAN controller Id is logical controller Id (e.g. id=0 is CAN_C) channel
 *       is equal to controllerId in the implementation.
 *
 *    Drivers:
 *      There is only support for one driver and that is the on-chip CAN.
 *
 *    Configuration:
 *      3.1.5 CANIF_NUMBER_OF_TXBUFFERS is defined to be the same as for 4.x, ie
 *      only have 1 buffer for each L-PDU. In 3.1.5 this was setable.
 *
 *
 *
 */
/* ----------------------------[includes]------------------------------------*/
#include "mid_S32kToAutoChip_Hal.h"

#include "CanIf.h"
//#include "mid_can.h"
#include "app_can.h"
#include "Can.h"
#include "CanIf_Cbk.h"
#include <string.h>

#ifdef USE_PDUR
#include "PduR.h"
#endif

#if defined(USE_CANTP)
#include "CanTp_Cbk.h"
#endif

#if defined(USE_CANNM)
#include "CanNm.h"
#endif
/* ----------------------------[Version check]------------------------------*/

/* ----------------------------[Config check]------------------------------*/

/* ----------------------------[private define]------------------------------*/

/* IMPROVMENT: Move to config */

#define EXTENDED_CANID_MAX			0x1FFFFFFF
#define STANDARD_CANID_MAX			0x000007FF
#define EXT_ID_BIT_POS				31
#define EXT_ID_STD_ID_START_BIT		18

#define CANIF_FALSE 0
#define CANIF_TRUE 1

#define    CANIF_REMOTE_FRAME    0
#define    CANIF_DATA_FRAME    1

/* ----------------------------[private macro]-------------------------------*/
#define IS_EXTENDED_CAN_ID(_x)		(0 != (_x & (1ul<<EXT_ID_BIT_POS)))

#define IS_VALID_CONTROLLER_MODE(_x) \
        ((CANIF_CS_STARTED == (_x)) || \
        (CANIF_CS_SLEEP == (_x)) || \
        (CANIF_CS_STOPPED == (_x)))

/* ----------------------------[private typedef]-----------------------------*/

typedef struct
{
	bool						initRun;
	CanIf_ControllerModeType	ControllerMode;
	CanIf_PduGetModeType		PduMode;
} CanIf_GlobalType;


/* ----------------------------[private function prototypes]-----------------*/
/* ----------------------------[private variables]---------------------------*/
CanIf_GlobalType CanIf_Global;

/* Global configure */
static const CanIf_ConfigType *CanIf_ConfigPtr;

/* Declared in Can_Cfg.c */
extern const CanIf_DispatchConfigType CanIfDispatchConfig;


/* ----------------------------[private functions]---------------------------*/
/* ----------------------------[public functions]----------------------------*/

/* IMPROVMENT: Generator changes
 *
 * - CanIfUserRxIndication should be set according to it's type, e.g
 *    CanNm_RxIndication, PduR_CanIfRxIndication, CanTp_RxIndication, J1939Tp_RxIndication
 *    What to do with "special"?
 * -  The number of PDU's should be generated to CANIF_NUM_TX_LPDU
 *
 *
 *
 * */


/*FUNCTION**********************************************************************
 *
 * Function Name : CanIf_Init
 * Description   : 
 *
 *END**************************************************************************/
void CanIf_Init(const CanIf_ConfigType *configPtr) 
{
	/* buffers and flags must be cleared when support is added */
	/* CCMSM enters CANIF_CS_INIT -> clear stored wakeup events */
	CanIf_ConfigPtr = configPtr;
	/* These all cooks down to controller mode CANIF_CS_STOPPED */

	CanIf_Global.ControllerMode = CANIF_CS_STOPPED;
	/* ControllerOnEnterMode(channel, CANIF_CS_STOPPED); */
	/* No req but still.. : PDU mode to OFFLINE */
	CanIf_Global.PduMode = CANIF_GET_OFFLINE;
	CanIf_Global.initRun = CANIF_TRUE;
}

extern void TCAN1043_OperatingMode (CanIf_ControllerModeType mode);
/*FUNCTION**********************************************************************
 *
 * Function Name : CanIf_SetControllerMode
 * Description   : 
 *
 *END**************************************************************************/
Std_ReturnType CanIf_SetControllerMode( CanIf_ControllerModeType ControllerMode )
{
	Std_ReturnType ret = E_OK;
		switch(ControllerMode) {

			case CANIF_CS_STARTED:
				TCAN1043_OperatingMode(CANIF_CS_STARTED);
				break;
			case CANIF_CS_SLEEP:
				TCAN1043_OperatingMode(CANIF_CS_SLEEP);
				break;
			default:
				ret = E_NOT_OK;
				break;
		}
	if(E_OK == ret) {
		CanIf_Global.ControllerMode = ControllerMode;
	}

	return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : CanIf_GetControllerMode
 * Description   : 
 *
 *END**************************************************************************/
Enum_Result_t CanIf_GetControllerMode(CanIf_ControllerModeType *ControllerModePtr) 
{
	*ControllerModePtr = CanIf_Global.ControllerMode;

	return E_OK;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : CanIf_Transmit
 * Description   : 
 *
 *END**************************************************************************/
Enum_Result_t CanIf_Transmit(PduIdType CanTxPduId, const PduInfoType *PduInfoPtr) 
{
    Enum_Result_t ret = E_OK;
	const CanIf_TxPduConfigType *txPduPtr;
    txPduPtr = &CanIf_ConfigPtr->InitConfig->CanIfTxPduConfigPtr[CanTxPduId];

/*############################################################################################*/
    if( CANIF_GET_OFFLINE == CanIf_Global.PduMode || CANIF_GET_RX_ONLINE == CanIf_Global.PduMode ) {
		//DET_REPORT_ERROR(CANIF_TRANSMIT_ID, CANIF_E_STOPPED);
        return E_NOT_OK;
    }
    if( CANIF_CS_STARTED != CanIf_Global.ControllerMode ) {
		//DET_REPORT_ERROR(CANIF_TRANSMIT_ID, CANIF_E_STOPPED);
        return E_NOT_OK;
    }
/*############################################################################################*/
    if( (CANIF_GET_OFFLINE_ACTIVE == CanIf_Global.PduMode) ||
		(CANIF_GET_OFFLINE_ACTIVE_RX_ONLINE == CanIf_Global.PduMode) ) 
	{
        if(NULL != txPduPtr->CanIfUserTxConfirmation ){
			txPduPtr->CanIfUserTxConfirmation(txPduPtr->CanIfTxPduId);
	    }
        return E_OK;
    }

	if(CANBusState(0) == CAN_NORMAL)
   	{
		struct_canMsg_t canMsg;
		canMsg.Id = txPduPtr->CanIfCanTxPduIdCanId;
		canMsg.IdType = txPduPtr->CanIfTxPduIdCanIdType;
		canMsg.Dlc = txPduPtr->CanIfCanTxPduIdDlc;
		memcpy((void *)&canMsg.Data[0], PduInfoPtr->SduDataPtr, txPduPtr->CanIfCanTxPduIdDlc);

		ret = mid_canWrite( 0, &canMsg );

		if(E_OK == ret)
		{
			if(NULL != txPduPtr->CanIfUserTxConfirmation ){
				txPduPtr->CanIfUserTxConfirmation(txPduPtr->CanIfTxPduId);
		    }
		}
	}
    return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : CanIf_TxConfirmation
 * Description   : 
 *
 *END**************************************************************************/
void CanIf_TxConfirmation( PduIdType canTxPduId )
{
    const CanIf_TxPduConfigType *txPduPtr;
    txPduPtr = &CanIf_ConfigPtr->InitConfig->CanIfTxPduConfigPtr[canTxPduId];

	if(NULL != txPduPtr->CanIfUserTxConfirmation ){
		txPduPtr->CanIfUserTxConfirmation(txPduPtr->CanIfTxPduId);
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : CanIf_RxIndication
 * Description   : 
 *
 *END**************************************************************************/
void CanIf_RxIndication( Can_IdType CanId, uint8_t CanDlc, const uint8_t *CanSduPtr )
{
    bool pduMatch = FALSE;
	PduInfoType pduInfo;
    const CanIf_RxPduConfigType *rxPduCfgPtr =  CanIf_ConfigPtr->InitConfig->CanIfRxPduConfigPtr;

    for(uint16_t i = 0; (i < CanIf_ConfigPtr->InitConfig->CanIfNumberOfCanRxPduIds) && !pduMatch; i++, rxPduCfgPtr++ ) 
	{
        /* if( ((canId & rxPduCfgPtr->CanIfCanRxPduCanIdMask) <= rxPduCfgPtr->CanIfCanRxPduUpperCanId) &&
        	((canId & rxPduCfgPtr->CanIfCanRxPduCanIdMask) >= rxPduCfgPtr->CanIfCanRxPduLowerCanId) )  */
		if((CanId & rxPduCfgPtr->CanIfCanRxPduCanIdMask) 
		    == (rxPduCfgPtr->CanIfCanRxPduCanId & rxPduCfgPtr->CanIfCanRxPduCanIdMask))
        {
            pduMatch = TRUE;
        } 
		else 
        {
            /* Did not match. Next entry */
        }
	}

    if( pduMatch ) 
    {
        rxPduCfgPtr--;
		
		switch (rxPduCfgPtr->CanIfRxUserType) 
		{
			case CANIF_USER_TYPE_CAN_SPECIAL:
			{
				((CanIf_FuncTypeCanSpecial) (rxPduCfgPtr->CanIfUserRxIndication))(
						rxPduCfgPtr->CanIfCanRxPduHrhRef->CanIfCanControllerHrhIdRef,
						rxPduCfgPtr->CanIfCanRxPduId, CanSduPtr, CanDlc, CanId);
			}
			break;

			case CANIF_USER_TYPE_CAN_NM:
#if defined(USE_CANNM)
				pduInfo.SduLength = CanDlc;
				pduInfo.SduDataPtr = (uint8 *)CanSduPtr;
				CanNm_RxIndication(rxPduCfgPtr->CanIfCanRxPduId,&pduInfo);
#endif
			break;

			case CANIF_USER_TYPE_CAN_PDUR:
#if defined(USE_PDUR) && (PDUR_CANIF_SUPPORT == STD_ON)
				pduInfo.SduLength = CanDlc;
				pduInfo.SduDataPtr = (uint8 *)CanSduPtr;
				PduR_CanIfRxIndication(rxPduCfgPtr->CanIfCanRxPduId,&pduInfo);
#endif
			break;

			case CANIF_USER_TYPE_CAN_TP:
#if defined(USE_CANTP)
				pduInfo.SduLength = CanDlc;
				pduInfo.SduDataPtr = (uint8 *) CanSduPtr;
				if(pduInfo.SduLength == 8)
				{
					#ifdef USE_CANNM
					nm_activate_event(E_DIAGNOSE_SWITCH_CMD, ON);
					#endif
					CanTp_RxIndication(rxPduCfgPtr->CanIfCanRxPduId, &pduInfo);
				}
#endif
			break;
		}
	}
}


/*FUNCTION**********************************************************************
 *
 * Function Name : CanIf_SetPduMode
 * Description   : 
 *
 *END**************************************************************************/
Enum_Result_t CanIf_SetPduMode( CanIf_PduSetModeType PduModeRequest )
{
	/* NOTE: The channel id is used and not the controller */
	Enum_Result_t ret = E_OK;
	CanIf_PduGetModeType currMode;
	CanIf_PduGetModeType newMode;

	currMode = CanIf_Global.PduMode;
	newMode = currMode;

	switch(PduModeRequest) {
	case CANIF_SET_OFFLINE:
		newMode = CANIF_GET_OFFLINE;
		break;
	case CANIF_SET_ONLINE:
	    newMode = CANIF_GET_ONLINE;
	    break;
	case CANIF_SET_RX_OFFLINE:
		if( CANIF_GET_ONLINE == currMode ) {
			newMode = CANIF_GET_TX_ONLINE;
		} else if( CANIF_GET_RX_ONLINE == currMode ) {
			newMode = CANIF_GET_OFFLINE;
		} else if( CANIF_GET_OFFLINE_ACTIVE_RX_ONLINE == currMode ) {
			newMode = CANIF_GET_OFFLINE_ACTIVE;
		}
		break;
	case CANIF_SET_RX_ONLINE:
		if(CANIF_GET_TX_ONLINE == currMode ) {
			newMode = CANIF_GET_ONLINE;
		} else if( CANIF_GET_OFFLINE == currMode ) {
			newMode = CANIF_GET_RX_ONLINE;
		} else if( CANIF_GET_OFFLINE_ACTIVE == currMode ) {
			newMode = CANIF_GET_OFFLINE_ACTIVE_RX_ONLINE;
		}
		break;
	case CANIF_SET_TX_OFFLINE:
		if( (CANIF_GET_ONLINE == currMode) || (CANIF_GET_OFFLINE_ACTIVE_RX_ONLINE == currMode) ) {
			newMode = CANIF_GET_RX_ONLINE;
		} else if( (CANIF_GET_TX_ONLINE == currMode) || (CANIF_GET_OFFLINE_ACTIVE == currMode) ) {
			newMode = CANIF_GET_OFFLINE;
		}
		break;
	case CANIF_SET_TX_OFFLINE_ACTIVE:
		if( CANIF_GET_OFFLINE == currMode || CANIF_GET_TX_ONLINE == currMode) {
			newMode = CANIF_GET_OFFLINE_ACTIVE;
		} else if( (CANIF_GET_ONLINE == currMode) || (CANIF_GET_RX_ONLINE == currMode) ) {
			newMode = CANIF_GET_OFFLINE_ACTIVE_RX_ONLINE;
		}
		break;
	case CANIF_SET_TX_ONLINE:
		if( CANIF_GET_OFFLINE == currMode ) {
			newMode = CANIF_GET_TX_ONLINE;
		} else if( (CANIF_GET_RX_ONLINE == currMode) || (CANIF_GET_OFFLINE_ACTIVE_RX_ONLINE == currMode) ) {
			newMode = CANIF_GET_ONLINE;
		} else if (CANIF_GET_OFFLINE_ACTIVE == currMode ) {
			newMode = CANIF_GET_TX_ONLINE;
		}
		break;
	default:
		//		DET_REPORT_ERROR(CANIF_SETPDUMODE_ID, CANIF_E_PARAM_PDUMODE);
		ret = E_NOT_OK;
		break;
	}

	if((CANIF_GET_OFFLINE == newMode)||(CANIF_GET_OFFLINE_ACTIVE == newMode))
		CanIf_SetControllerMode(CANIF_CS_SLEEP);
	else
		CanIf_SetControllerMode(CANIF_CS_STARTED);
	CanIf_Global.PduMode = newMode;

	return ret;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : CanIf_GetPduMode
 * Description   : 
 *
 *END**************************************************************************/
Std_ReturnType CanIf_GetPduMode( CanIf_PduGetModeType *PduModePtr )
{
	*PduModePtr = CanIf_Global.PduMode;
	return E_OK;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : CanIf_ControllerBusOff
 * Description   : 
 *
 *END**************************************************************************/
void CanIf_ControllerBusOff( uint8 Controller )
{
    Controller = Controller;
}
void CanIf_SetWakeupEvent( uint8 Controller )
{
	Controller = Controller;
}
void CanIf_User_BusoffNotification(uint8 Controller)
{
  	Controller = Controller;
}
void CanIf_User_ErrorNotification(uint8 Controller,Can_Arc_ErrorType err)
{
  	Controller = Controller;
}
void CanIf_ControllerModeIndication(uint8 Controller,CanIf_ControllerModeType Mode)
{
	Controller = Controller;
}
